#ifndef ADL_UART_H_
#define ADL_UART_H_

#define UART0	0
#define UART2	2
#define UART3	3

#define UART0_BASE_ADDR		0xE000C000
#define UART2_BASE_ADDR		0xE0078000
#define UART3_BASE_ADDR		0xE007C000

#define UART_BASE_ADDR(uart)	(\
								(uart == UART0) ? UART0_BASE_ADDR :\
								(uart == UART2) ? UART2_BASE_ADDR :\
								UART3_BASE_ADDR\
								)

#define RBR(uart)          (*(volatile U32 *)(UART_BASE_ADDR(uart) + 0x00))
#define THR(uart)          (*(volatile U32 *)(UART_BASE_ADDR(uart) + 0x00))
#define DLL(uart)          (*(volatile U32 *)(UART_BASE_ADDR(uart) + 0x00))
#define DLM(uart)          (*(volatile U32 *)(UART_BASE_ADDR(uart) + 0x04))
#define IER(uart)          (*(volatile U32 *)(UART_BASE_ADDR(uart) + 0x04))
#define IIR(uart)          (*(volatile U32 *)(UART_BASE_ADDR(uart) + 0x08))
#define FCR(uart)          (*(volatile U32 *)(UART_BASE_ADDR(uart) + 0x08))
#define LCR(uart)          (*(volatile U32 *)(UART_BASE_ADDR(uart) + 0x0C))
#define LSR(uart)          (*(volatile U32 *)(UART_BASE_ADDR(uart) + 0x14))
#define SCR(uart)          (*(volatile U32 *)(UART_BASE_ADDR(uart) + 0x1C))
#define ACR(uart)          (*(volatile U32 *)(UART_BASE_ADDR(uart) + 0x20))
#define ICR(uart)          (*(volatile U32 *)(UART_BASE_ADDR(uart) + 0x24))
#define FDR(uart)          (*(volatile U32 *)(UART_BASE_ADDR(uart) + 0x28))
#define TER(uart)          (*(volatile U32 *)(UART_BASE_ADDR(uart) + 0x30))

// Receive Data Available interrupt
#define IER_RBR		0x01
// Data Transmited interrupt
#define IER_THRE	0x02
// RX line status interrupts
#define IER_RLS		0x04

// Data Transmited interrupt
#define IIR_THRE	0x01
// Receive Data Available interrupt
#define IIR_RDA		0x02
// RX line status interrupts
#define IIR_RLS		0x03
// Character Time-out Indicator interrupt
#define IIR_CTI		0x06

#define UART_5_BITS_DATA_LENGTH	0x00
#define UART_6_BITS_DATA_LENGTH	0x01
#define UART_7_BITS_DATA_LENGTH	0x02
#define UART_8_BITS_DATA_LENGTH	0x03

#define STOP_BIT_1	0
#define STOP_BIT_2	1

#define ODD_PARITY		0x00
#define EVEN_PARITY 	0x01
#define FORCED_1_PARITY	0x02
#define FORCED_0_PARITY	0x03

typedef struct {
	U32 wordLength : 2;
	U32 stopBit : 1;
	U32 parityEnable : 1;
	U32 parity : 2;
	U32 breakControl : 1;
	U32 divisorLatchAccess : 1;
} LineControlRegister;

// Receiver Data Ready
#define LSR_RDR		0x01
// Overrun Error
#define LSR_OE		0x02
// Parity Error
#define LSR_PE		0x04
// Framing Error
#define LSR_FE		0x08
// Break Interrupt
#define LSR_BI		0x10
// Transmission finished
#define LSR_THRE	0x20
// Transmitter Empty
#define LSR_TEMT	0x40
// Error in RX FIFO
#define LSR_RXFE	0x80

typedef struct {
	U32 DIVADDVAL : 4;
	U32 MULVAL : 4;
} FractionalDivisorRegister;


// Obs.: Before reading data, adl_uart_GET_LINE_STATUS must be called.
#define adl_uart_READ_RECEIVED_DATA(uart)	RBR(uart)

#define adl_uart_SEND_DATA(uart, data)	THR(uart) = data;

#define adl_uart_GET_BAUDRATE_DIVISOR(uart)	((U16)((DLM(uart) << 8) | (DLL(uart))))
// Obs.: Before set baudrate, divisor latch access muste be enabled (adl_uart_ENABLE_BAUDRATE_DLA)
#define adl_uart_SET_BAUDRATE_DIVISOR(uart, divisor)	DLL(uart) = (divisor & 0xFF);\
														DLM(uart) = (divisor >> 8);

#define adl_uart_GET_FRACTIONAL_BAUDRATE_DIVISOR(uart)			((*((FractionalDivisorRegister *)(&FDR(uart)))).DIVADDVAL)
#define adl_uart_SET_FRACTIONAL_BAUDRATE_DIVISOR(uart, divisor)	((*((FractionalDivisorRegister *)(&FDR(uart)))).DIVADDVAL = divisor)

#define adl_uart_GET_FRACTIONAL_BAUDRATE_MULTIPLIER(uart)				((*((FractionalDivisorRegister *)(&FDR(uart)))).MULVAL)
#define adl_uart_SET_FRACTIONAL_BAUDRATE_MULTIPLIER(uart, multiplier)	((*((FractionalDivisorRegister *)(&FDR(uart)))).MULVAL = multiplier)

#define adl_uart_ENABLE_RDA_INTERRUPT(uart)		(IER(uart) |= IER_RBR)
#define adl_uart_DISABLE_RDA_INTERRUPT(uart)	(IER(uart) &= ~(IER_RBR))
#define adl_uart_IS_ENABLE_RDA_INTERRUPT(uart)	(IER(uart) & IER_RBR)

#define adl_uart_ENABLE_THRE_INTERRUPT(uart)	(IER(uart) |= IER_THRE)
#define adl_uart_DISABLE_THRE_INTERRUPT(uart)	(IER(uart) &= ~(IER_THRE))
#define adl_uart_IS_ENABLE_THRE_INTERRUPT(uart)	(IER(uart) & IER_THRE)

#define adl_uart_ENABLE_RLS_INTERRUPT(uart)		(IER(uart) |= IER_RLS)
#define adl_uart_DISABLE_RLS_INTERRUPT(uart)	(IER(uart) &= ~(IER_RLS))
#define adl_uart_IS_ENABLE_RLS_INTERRUPT(uart)	(IER(uart) & IER_RLS)

#define adl_uart_GET_INTERRUPT_ID(uart)	((IIR(uart) >> 1) & 0x07)

#define adl_uart_GET_DATA_LENGTH(uart)			((*((LineControlRegister *)(&LCR(uart)))).wordLength)
#define adl_uart_SET_DATA_LENGTH(uart, setting)	((*((LineControlRegister *)(&LCR(uart)))).wordLength = setting)

#define adl_uart_GET_STOP_BIT(uart)				((*((LineControlRegister *)(&LCR(uart)))).stopBit)
#define adl_uart_SET_STOP_BIT(uart, setting)	((*((LineControlRegister *)(&LCR(uart)))).stopBit = setting)

#define adl_uart_IS_ENABLE_PARITY(uart)				((*((LineControlRegister *)(&LCR(uart)))).parityEnable)
#define adl_uart_SET_ENABLE_PARITY(uart, enable)	((*((LineControlRegister *)(&LCR(uart)))).parityEnable = enable)
#define adl_uart_GET_PARITY(uart)					((*((LineControlRegister *)(&LCR(uart)))).parity)
#define adl_uart_SET_PARITY(uart, setting)			((*((LineControlRegister *)(&LCR(uart)))).parity = setting)

#define adl_uart_ENABLE_BREAK_TRANSMISSION(uart)	((*((LineControlRegister *)(&LCR(uart)))).breakControl = 1)
#define adl_uart_DISABLE_BREAK_TRANSMISSION(uart)	((*((LineControlRegister *)(&LCR(uart)))).breakControl = 0)

#define adl_uart_ENABLE_BAUDRATE_DLA(uart)		((*((LineControlRegister *)(&LCR(uart)))).divisorLatchAccess = 1)
#define adl_uart_DISABLE_BAUDRATE_DLA(uart)		((*((LineControlRegister *)(&LCR(uart)))).divisorLatchAccess = 0)

#define adl_uart_IS_RECEIVE_DATA_READY(uart)	(LSR(uart) & LSR_RDR)

#define adl_uart_IS_OVERRUN_ERROR(uart)			(LSR(uart) & LSR_OE)

#define adl_uart_IS_PARITY_ERROR(uart)			(LSR(uart) & LSR_PE)

#define adl_uart_IS_FRAMING_ERROR(uart)			(LSR(uart) & LSR_FE)

#define adl_uart_IS_BREAK_INTERRUPT(uart)		(LSR(uart) & LSR_BI)

#define adl_uart_IS_TRANSMISSION_READY(uart)	(LSR(uart) & LSR_THRE)

#define adl_uart_IS_RX_FIFO_ERROR(uart)			(LSR(uart) & LSR_RXFE)


#endif /*ADL_UART_H_*/
